-- ======================================================================
-- Hell Logic Sniffer Addon 
-- 
-- Copyright 2013 Hell-Prototypes
--
-- http://www.hellprototypes.com/
-- ======================================================================

ModuleClass = "LS_DECODER"
ModuleName  = "SPI"
ModuleTip   = "To decode SPI data"

--------------------------------------------------------------------------------
g_ch_num_mosi = 0
g_ch_num_miso = 0
g_ch_num_sck  = 0
g_ch_num_ss   = 0
g_decode_mode = 0

g_sck_data_clocked_table = {}

g_byte_mask_msb_first = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
g_byte_mask_lsb_first = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}

g_byte_shift_mask = {}

function main ()
    LS_API.DebugMsg("===SPI_Decode.lua main function called===")
    -- param check
    if type(LS_PARAM) ~= "table" then
    	LS_API.MessageBox("<SPI> LS_PARAM was not a table class")
		return
    end
    if #LS_PARAM ~= 6 then
    	LS_API.MessageBox("<SPI> LS_PARAM's size must = 5, size = " .. #LS_PARAM)
    end
    
    for i=1, #LS_PARAM - 2 do
    	tmp = LS_PARAM[i]
    	for j=i+1, #LS_PARAM - 2 do
    		if tmp == LS_PARAM[j] then
    			LS_API.MessageBox("<SPI> Channel number select error, channel: <" .. tmp .. ">")
    			return
    		end
    	end
    end
    
    -- get SPI param
    g_ch_num_mosi = LS_PARAM[1]
    g_ch_num_miso = LS_PARAM[2]
    g_ch_num_sck  = LS_PARAM[3]
    g_ch_num_ss   = LS_PARAM[4]
    g_decode_mode = LS_PARAM[5]
    if LS_PARAM[6] == 0 then --LSB
        g_byte_shift_mask = g_byte_mask_lsb_first
    else --MSB
        g_byte_shift_mask = g_byte_mask_msb_first
    end
    
    -- LS_API.DebugMsg("SPI param, mosi: " .. g_ch_num_mosi ..  ", miso: " .. g_ch_num_miso ..  ", sck: " .. g_ch_num_sck ..  ", ss: " .. g_ch_num_ss ..  ", mode: " .. g_decode_mode)

	-- get data clocked table
	get_sck_data_clocked_table()
	
	local byte_bit_index = 1
	local decode_out_index = 3
	local bit_index = 0
	local mosi_level = 0
	local miso_level = 0
	local mosi_byte_data = 0
	local miso_byte_data = 0
	local mosi_decode_out = {}
	local miso_decode_out = {}
	for table_index = 1, #g_sck_data_clocked_table do
		--LS_API.DebugMsg("<SPI>table_index: " .. table_index)
		bit_index = g_sck_data_clocked_table[table_index]
		if (g_ch_num_ss < 0) or (LS_API.GetChannelLevelByIndex(g_ch_num_ss, bit_index) == 0) then
			mosi_level = get_mosi_bit_level( bit_index )
			if mosi_level then
				mosi_byte_data = mosi_byte_data + g_byte_shift_mask[byte_bit_index]
			end
			miso_level = get_miso_bit_level( bit_index )
			if miso_level then
				miso_byte_data = miso_byte_data + g_byte_shift_mask[byte_bit_index]
			end
			
			--LS_API.DebugMsg("<SPI>byte_bit_index = " .. byte_bit_index)
			
			if byte_bit_index == 1 then
				mosi_decode_out[1] = bit_index
				miso_decode_out[1] = -bit_index
				--LS_API.DebugMsg("<SPI>bit_index = " .. bit_index * 2)
			end

			mosi_decode_out[decode_out_index] = bit_index
			miso_decode_out[decode_out_index] = bit_index
			decode_out_index = decode_out_index + 1

			if byte_bit_index == 8 then
				mosi_decode_out[2] = mosi_byte_data
				miso_decode_out[2] = miso_byte_data

				if not commit_result_to_host(mosi_decode_out) then
					return
				end
				if not commit_result_to_host(miso_decode_out) then
					return
				end

				decode_out_index = 3
				mosi_byte_data = 0
				miso_byte_data = 0
				--mosi_decode_out = {}
				--miso_decode_out = {}
				
				byte_bit_index = 1
			else
				byte_bit_index = byte_bit_index + 1
			end
		else
			decode_out_index = 3
			mosi_byte_data = 0
			miso_byte_data = 0
			byte_bit_index = 1
		end
	end
end

--------------------------------------------------------------------------------
function get_sck_data_clocked_table()
	local level_flag = 0
	if g_decode_mode == 0 or g_decode_mode == 3 then
		g_sck_data_clocked_table = LS_API.GetChannelPosedgeTable(g_ch_num_sck)--上升沿
	elseif g_decode_mode == 1 or g_decode_mode == 2 then
		g_sck_data_clocked_table = LS_API.GetChannelNegedgeTable(g_ch_num_sck)--下降沿
	else
		LS_API.DebugMsg("Unsupport decode mode: " .. g_decode_mode)
		return nil
	end
end
--------------------------------------------------------------------------------
function get_mosi_bit_level( bit_index )
    local level = LS_API.GetChannelLevelByIndex(g_ch_num_mosi, bit_index);
	if level == 1 then
		return true
	else
		return false
    end
end

--------------------------------------------------------------------------------
function get_miso_bit_level( bit_index )
    local level = LS_API.GetChannelLevelByIndex(g_ch_num_miso, bit_index);
	if level == 1 then
		return true
	else
		return false
    end
end

--------------------------------------------------------------------------------
function commit_result_to_host(tab)
	-- LS_API.DebugMsg("<SPI>tab = " .. tab[1] * 2)
	ret = LS_API.DecodeElementPushBack(tab)
	if ret ~= 0 then
		LS_API.MessageBox("<SPI> Fail to push decode miso result to host, ret =" .. ret)
		return false
	end
	return true
end
